#!/usr/bin/python2.7
# -*- coding: utf-8 -*-

import sys
import ConfigParser

from PyQt4 import QtGui, QtCore

from libVirgil import i18n as virgilI18N

VERSION = "0.0.1B"
REVISION = "$Revision: 34 $".replace("$","") #SVN Attribute that gets updated on each check-in (we remove the $ $'s to make it readable

CATEGORY_REFERENCE = 1

class TreeItem(object):
    def __init__(self, data, parent=None):
        self.parentItem = parent
        self.itemData = data
        self.childItems = []
        self.expanded = False
        self.isCodeScheme = False
        self.isCode = False

    def appendChild(self, item):
        self.childItems.append(item)

    def child(self, row):
        return self.childItems[row]

    def childCount(self):
        return len(self.childItems)

    def columnCount(self):
        return len(self.itemData)

    def isExpanded(self,value=None):
        if value is None:
            return self.expanded
        else:   
            self.expanded = value

    def data(self, column):
        try:
            return self.itemData[column]
        except IndexError:
            return None

    def parent(self):
        return self.parentItem

    def row(self):
        if self.parentItem:
            return self.parentItem.childItems.index(self)
        return 0
    def setLabel(self,label):
        self.itemData[1] = label

    def setCodeValue(self,label):
        raise NotImplementedError()
    def getCodeID(self):
        raise NotImplementedError()
    def setLanguage(self,lang):
        raise NotImplementedError()
    def addChildCode(self,lang):
        raise NotImplementedError()
    def clearChildItems(self):
        self.childItems = []

class CodeSchemeItem(TreeItem):
    def __init__(self, data, parent=None):
        TreeItem.__init__(self,[data['value'],data['label']],parent)
#        self.appendChild(PlaceholderItem(['-','Loading'],parent=self))
        self.item = data
        self.itemData = ["*",self.item['label']]
        self.isCodeScheme = True

    def getCodeID(self):
        return self.item['id']
    def setCodeValue(self,label):
        pass
    def setLanguage(self,lang):
        self.setLabel(self.item['labels'].get(lang,"*** %s translation not available"%virgilI18N.iso639CodeToString(lang)))
    def removePlaceholder(self):
        self.childItems.pop(0) #After all children are loaded, remove the placeholder
    def addChildCode(self):
        pass

class CodeItem(TreeItem):
    def __init__(self, data, parent=None):
        TreeItem.__init__(self,[data['value'],data['label']],parent)
        self.appendChild(PlaceholderItem(['-','Loading'],parent=self))
        self.item = data
        self.isCode = True
        
    def removePlaceholder(self):
        self.childItems.pop(0) #After all children are loaded, remove the placeholder
    def getCodeValue(self):
        return self.item['value']
    def setCodeValue(self,value):
        self.item['value'] = value
        self.itemData[0] = value

    def getCodeID(self):
        return self.item['id']
    def setLanguage(self,lang):
        self.setLabel(self.item['labels'].get(lang,"%s translation not available"%virgilI18N.iso639CodeToString(lang)))
    def addChildCode(self):
        pass

class PlaceholderItem(TreeItem):
    def __init__(self, data, parent=None):
        TreeItem.__init__(self,data,parent)
        self.isExpanded(True)

    def getCodeID(self):
        return None

    def setLanguage(self,lang):
        pass

class DDITreeModel(QtCore.QAbstractItemModel):
    def __init__(self, ddi, parent=None, defaultLang=None):
        super(DDITreeModel, self).__init__(parent)
        self.editableFields   = {'value':True,'labels':True,'descriptions':True}    # The possible editable fields on the form the treeModel needs to know about

        self.ddi = ddi
        self.rootItem = PlaceholderItem(['Value','Label'])
        if self.ddi is not None:
            self.languages = list(set(self.ddi.labelLanguages()))
            if len(self.languages) == 0:
                self.languages = ['en-au']
            self.languages.sort()
            self.selectedLanguage = list(self.languages)[0]
            self.setupModelData(ddi, self.rootItem)
        else:
            pass # In production cases there should ALWAYS BE A DDI FILE PASSED IN
            self.languages = list(set(['en-au']))
            self.selectedLanguage = "en-au"

    def setupModelData(self, lines, parent):
        for item in self.ddi.getTopLevelCodeLists():
            treeitem = CodeSchemeItem(item, parent)
            parent.appendChild(treeitem)
            treeitem.expanded =  True
            for id,value,catref in self.ddi.getChildCodes(treeitem.getCodeID()):
                category  = self.ddi.getCategory(catref)
                item = {'id': id, 'value': value, 'labels': category['labels'],'label':""}

                child = CodeItem(data=item,parent=treeitem)
                child.setLanguage(self.selectedLanguage)

                treeitem.appendChild(child)

    def getLanguageIndex(self,lang):
        if lang in self.languages:
            return self.languages.index(lang)
        else:
            return -1
    def getLanguages(self):
        return self.languages
    def setLanguageByIndex(self,i):
        if 0 <= i <= len(self.languages):
            self.setLanguage(self.languages[i])

    def addLanguage(self,lang):
        self.languages = list(set(self.languages) | {lang})
        self.languages.sort()

    def addCodeList(self,codeSID,categorySID,labels,descriptions):
        item = self.ddi.newClassification(codeSID,categorySID,labels,descriptions)
        item['id']    = codeSID
        item['value'] = None
        item['label'] = labels[self.selectedLanguage]
        treeitem = CodeSchemeItem(item, self.rootItem)
        self.rootItem.appendChild(treeitem)
        treeitem.clearChildItems()
#        indexR = self.createIndex(0,0,self.rootItem)
#        indexC = self.createIndex(self.rootItem.childCount(),1,self.rootItem)
#        self.emit(QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)'),indexR,indexC)
        
    def addCode(self,index,code):
        selected = index.internalPointer()
        code['parent']    = selected.getCodeID()
        codeSchemeID      = self.ddi.getCodeSchemeFromCode(code['parent'])
        categorySchemeID  = self.ddi.getCategorySchemeFromCode(code['parent'])
        self.ddi.newCodeCategory(code,codeSchemeID,categorySchemeID)
        selected.isExpanded(False)
        self.collapse(index)
        self.expand(index)        

    def setLanguage(self,lang):
        if lang in self.languages:
            self.selectedLanguage = lang
            items = [self.rootItem]
            for i in items:
                items += i.childItems
                i.setLanguage(lang)
                parent = i.parent()
                if parent is not None and i.getCodeID() is not None:
                    r = parent.childItems.index(i)
                    index = self.createIndex(r,0,i.parent())
                    sibling = self.createIndex(r,1,i.parent())
                    self.emit(QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)'),index,sibling)
    def canFetchMore(self,parent):
        return False #not parent.internalPointer().expanded

    def columnCount(self, parent):
        if parent.isValid():
            return parent.internalPointer().columnCount()
        else:
            return self.rootItem.columnCount()

    """
        returns selected category as hash and editable values as hash
    """
    def getCategory(self,index):
        selectedCategory = {}
        selected = index.internalPointer() 
        code_id = selected.getCodeID()
        editable = self.editableFields.copy()

        if selected.isCodeScheme == True:
            #we are in a top level item (ie. a CodeScheme) so we need to do different stuff...
            selectedCategory = self.ddi.getCategoryFromCodeScheme(code_id)
        elif selected.isCode == True:
            selectedCategory = self.ddi.getCategoryFromCode(code_id)
        else:
            # there is nothing to get
            pass

        if selected.isCodeScheme == True:
            editable['value'] = False
        
        return (selectedCategory,editable)

    def collapse(self,index):
        # Remove children and add a placeholder
        selected = index.internalPointer()
        selected.isExpanded(False)
        selected.childItems = []
        selected.appendChild(PlaceholderItem(['-','Loading'],parent=self))

    def setLabel(self,index,lang,value):
        item = index.internalPointer()
        sibling = index.sibling(index.row(),index.column()+1)
        if lang == self.selectedLanguage:
            item.setLabel(value)
            self.emit(QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)'),index,sibling)
    def getCodeValue(self,index):
        item = index.internalPointer()
        return item.getCodeValue()
    def setCodeValue(self,index,value):
        item = index.internalPointer()
        item.setCodeValue(value)
        self.emit(QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)'),index,index)

    def expand(self,index):
        if not index.isValid():
            return None
        item = index.internalPointer()
        if not item.isExpanded():
            item.isExpanded(True)
            for id,value,catref in self.ddi.getChildCodes(item.item['id']):
                category  = self.ddi.getCategory(catref)

                code = {'id': id, 'value': value, 'labels': category['labels'],'label':""}

                child = CodeItem(data=code,parent=item)
                child.setLanguage(self.selectedLanguage)


                item.appendChild(child)
            item.removePlaceholder()
        self.emit(QtCore.SIGNAL("layoutChanged()"))

    def fetchMore(self,parent):
        #print parent.internalPointer()
        pass

    def data(self, index, role):
        if not index.isValid():
            return None

        if role != QtCore.Qt.DisplayRole:
            return None

        item = index.internalPointer()

        return item.data(index.column())

    def getCodeID(self,index):
        if not index.isValid():
            return None
        item = index.internalPointer()
        return item.getCodeID()

    def supportedDragActions(self): 
        return QtCore.Qt.MoveAction
    def supportedDropActions(self): 
        return QtCore.Qt.MoveAction

    def getTextPlainFromIndexes(self,indexes):
        items = [] 
        for i in indexes:
            items.append(i.internalPointer())
        items = list(set(items))        # Remove dupes
        out = []
        for i in items:
            if i.isCode == True:
                out.append(self.ddi.getCodeAsText(lang=self.selectedLanguage,id=i.getCodeID(),depth=1))
            if i.isCodeScheme == True:
                out.append("CodeScheme")
        return "\n".join(out)

    def mimeTypes(self):
        return ['text/x-ddi-virgilID','text/xml+x-ddi-fragment']

    def mimeData(self, indexes):
        self.aboutToMove = indexes # set the indexes we are about to move, so we can use them on the drop

        mimedata = QtCore.QMimeData()
        mimedata.setData('text/x-ddi-virgilID', unicode(self)) # serialize our object name to check on the drop, in future when we support drag/drop between apps this will be useful
        mimedata.setData('text/plain', self.getTextPlainFromIndexes(indexes)) 

        return mimedata

    def dropMimeData(self, data, action, row, column, parent):

        if unicode(self) == data.data('text/x-ddi-virgilID'):
            obj = self.aboutToMove[0].internalPointer()         # The object we wish to move
            parent = parent.internalPointer()                   # The new parent object
            oldIndex = obj.parentItem.childItems.remove(obj)    # The previous index of the moving object
            self.setParent(obj,parent,row)
            
            self.emit(QtCore.SIGNAL('layoutChanged()'))
        else:
            pass # We've had a drop from another program


        self.aboutToMove = None
        return True


    def setParent(self,child,parent,row):
        oldparent = child.parentItem
        child.parentItem = parent
        if row == -1:
            parent.childItems.append(child) 
        else:
            parent.childItems.insert(row,child) 
        self.ddi.setCodeParent(child.getCodeID(),parent.getCodeID(),oldparent.getCodeID(),row)

    def flags(self, index):
        if not index.isValid():
            return QtCore.Qt.NoItemFlags

        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled

    def headerData(self, section, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self.rootItem.data(section)

        return None

    def index(self, row, column, parent):
        if not self.hasIndex(row, column, parent):
            return QtCore.QModelIndex()

        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()

        childItem = parentItem.child(row)
        if childItem:
            return self.createIndex(row, column, childItem)
        else:
            return QtCore.QModelIndex()

    def parent(self, index):
        if not index.isValid():
            return QtCore.QModelIndex()

        childItem = index.internalPointer()
        parentItem = childItem.parent()

        if parentItem == self.rootItem:
            return QtCore.QModelIndex()
        elif parentItem == None:
            return index
        else:
            return self.createIndex(parentItem.row(), 0, parentItem)

    def rowCount(self, parent):
        if parent.column() > 0:
            return 0

        if not parent.isValid():
            parentItem = self.rootItem
        else:
            parentItem = parent.internalPointer()

        return parentItem.childCount()

    def deleteItem(self,index):
        i = index.internalPointer()
        parent = i.parent()
        parent.childItems.remove(i) 
        self.ddi.deleteItem(i.getCodeID())
        parent.collapse()
        parent.expand()

